# Copyright 2005 James Bunton <james@delx.cjb.net>
# Licensed for distribution under the GPL version 2, check COPYING for details

import md5
import struct
import string

MSNP11_PRODUCT_ID = "PROD0090YUAUV{2B"
MSNP11_PRODUCT_KEY = "YMM8C_H7KCQ2S_KL"
MSNP11_MAGIC_NUM = 0x0E79A9C1


def doChallenge(chlData):
	md5digest = md5.md5(chlData + MSNP11_PRODUCT_KEY).digest()

	# Make array of md5 string ints
	md5Ints = struct.unpack("<llll", md5digest)
	md5Ints = [(x & 0x7fffffff) for x in md5Ints]

	# Make array of chl string ints
	chlData += MSNP11_PRODUCT_ID
	amount = 8 - len(chlData) % 8
	chlData += string.zfill("", amount)
	chlInts = struct.unpack("<%di" % (len(chlData)/4), chlData)

	# Make the key
	high = 0
	low = 0
	i = 0
	while i < len(chlInts) - 1:
		temp = chlInts[i]
		temp = (MSNP11_MAGIC_NUM * temp) % 0x7FFFFFFF
		temp += high
		temp = md5Ints[0] * temp + md5Ints[1]
		temp = temp % 0x7FFFFFFF

		high = chlInts[i + 1]
		high = (high + temp) % 0x7FFFFFFF
		high = md5Ints[2] * high + md5Ints[3]
		high = high % 0x7FFFFFFF

		low = low + high + temp

		i += 2

	high = littleEndify((high + md5Ints[1]) % 0x7FFFFFFF)
	low = littleEndify((low + md5Ints[3]) % 0x7FFFFFFF)
	key = (high << 32L) + low
	key = littleEndify(key, "Q")

	longs = [x for x in struct.unpack(">QQ", md5digest)]
	longs = [littleEndify(x, "Q") for x in longs]
	longs = [x ^ key for x in longs]
	longs = [littleEndify(abs(x), "Q") for x in longs]
	
	out = ""
	for x in longs:
		x = hex(x)
		x = x[2:len(x)-1]
		x = x.zfill(16)
		out += x.lower()
	
	return out

def littleEndify(num, c="L"):
	return struct.unpack(">" + c, struct.pack("<" + c, num))[0]

def passport_auth(hash, email, password):
		"""Logins into passport and obtains an ID used for
		authorization; it's a helper function for login"""
		import httplib
		import urllib

		try:
			nexus = urllib.urlopen('https://nexus.passport.com/rdr/pprdr.asp')
			h = nexus.headers
			purl = h['PassportURLs']

			d = {}
			for i in purl.split(','):
				key, val = i.split('=', 1)
				d[key] = val

			login_server = 'https://' + d['DALogin']
			login_host = d['DALogin'].split('/')[0]

			ahead =  'Passport1.4 OrgVerb=GET'
			ahead += ',OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom'
			ahead += ',sign-in=' + urllib.quote(email)
			ahead += ',pwd=' + urllib.quote(password)
			ahead += ',lc=1033,id=507,tw=40,fs=1,'
			ahead += 'ru=http%3A%2F%2Fmessenger%2Emsn%2Ecom,ct=0,'
			ahead += 'kpp=1,kv=5,ver=2.1.0173.1,tpf=' + hash
			headers = { 'Authorization': ahead }

			ls = httplib.HTTPSConnection(login_host)

			ls.request('GET', login_server, '', headers)
			resp = ls.getresponse()

			while resp.status == 302:
				login_server = resp.getheader('Location')
				login_host = login_server.split('/')[2]
				ls = httplib.HTTPSConnection(login_host)
				headers = { 'Authorization': ahead }
				ls.request('GET', login_server, '', headers)
				resp = ls.getresponse()

			if resp.status != 200:
				raise 'AuthError', [911, 'SSL Auth failed']

			try:
				ainfo = resp.getheader('Authentication-Info')
			except:
				ainfo = resp.getheader('WWW-Authenticate')

			d = {}

			for i in ainfo.split(','):
				key, val = i.split('=', 1)
				d[key] = val

			passportid = d['from-PP']
			passportid = passportid[1:-1]		# remove the "'"

			return passportid

		except:
			return False


